/*

Summary:
Use to convert string to basic types.

Remark:
These basic types are supported at present: char, unsigned char,
wchar_t, short, unsigned short, int, unsigned int, long,
unsigned long, long long and unsigned long long. Be aware that
float, double and long double are not be supported yet.

The string to be converted must fit numeric format exactly.
It means that the string cannot have any invalid char, even
blank chars, at its head or tail, or conversion would failed.

The parameter radix must be in the range 2 - 36.

Negative number cannnot convert to unsigned types. For example, 
"-1" converted to unsigned int will failed.

TryFromString returns true when conversion is succeed, and 
returns false when failed. If conversion failed, the output 
argument will not be changed.

FromString cannot determinate whether the conversion is succeed,
and it returns 0 when failed.

This header file will undefine max an min macro. Therefore, you 
cannot use max and min if you include Windows.h before this file.

Version:
0.1.0

LastUpdatedDate:
2012-12-11

CreatedDate:
2012-08-15

*/


#pragma once
#include <string>
#include <type_traits>
#include "CString.h"


#ifdef max
#undef max
#endif

#ifdef min
#undef min
#endif
	

namespace Zaf {
namespace String {
namespace __Internal {


template<typename ValueType>
struct __IsLesserThanLLong {
	static const bool Value = true;
};

template<>
struct __IsLesserThanLLong<long long> {
	static const bool Value = false;
};

template<>
struct __IsLesserThanLLong<unsigned long long> {
	static const bool Value = false;
};

template<typename ValueType>
struct __MakeLargerType {
	typedef typename std::conditional<
		__IsLesserThanLLong<ValueType>::Value, 
		typedef typename std::conditional<
			std::is_signed<ValueType>::value,
			long,
			unsigned long
		>::type,
		typedef typename std::conditional<
			std::is_signed<ValueType>::value,
			long long,
			unsigned long long
		>::type
	>::type Type;
};



template<typename ValueType, typename CharType>
struct __StrToULongWrapper {
	static typename unsigned long __Func(const CharType* begin, CharType** end, int radix) {
		return StrToULong(begin, end, radix);
	}
};

template<typename ValueType, typename CharType>
struct __StrToULLongWrapper {
	static typename unsigned long long __Func(const CharType* begin, CharType** end, int radix) {
		return StrToULLong(begin, end, radix);
	}
};


template<typename ValueType, typename CharType>
struct __SelectConverter {
	typedef typename std::conditional<
		__IsLesserThanLLong<ValueType>::Value, 
		__StrToULongWrapper<ValueType, CharType>, 
		__StrToULLongWrapper<ValueType, CharType>
	>::type Type;
};



template<typename ValueType, typename CharType>
bool __S2N_Dec(const CharType* begin, CharType** end, int radix, ValueType& value) {

	bool hasNegativeSign = (*begin == '-');

	__MakeLargerType<ValueType>::Type tmpValue = 
		__SelectConverter<ValueType, CharType>::Type::__Func(begin, end, radix);

	if (errno != 0) {
		return false;
	}

	if ((hasNegativeSign == true && tmpValue > 0) ||
		(hasNegativeSign == false && tmpValue < 0)) {
			return false;
	}

	if (tmpValue < std::numeric_limits<ValueType>::min() || tmpValue > std::numeric_limits<ValueType>::max()) {
		return false;
	}

	value = (ValueType)tmpValue;
	return true;
}



template<typename ValueType, typename CharType>
bool __S2N_NonDec(const CharType* begin, CharType** end, int radix, ValueType& value) {

	std::make_unsigned<__MakeLargerType<ValueType>::Type>::type tmpValue = 
		__SelectConverter<ValueType, CharType>::Type::__Func(begin, end, radix);

	if (errno != 0) {
		return false;
	}

	if (tmpValue > std::numeric_limits<std::make_unsigned<ValueType>::type >::max()) {
		return false;
	}

	value = (ValueType)tmpValue;
	return true;
}



template<typename ValueType, typename CharType>
bool __S2N(const CharType* begin, CharType** end, int radix, ValueType& value) {

	errno = 0;

	if (radix == 10) {
		return __S2N_Dec(begin, end, radix, value);
	}
	else {
		return __S2N_NonDec(begin, end, radix, value);
	}
}



}  // __Internal



#define __Zaf_FromString_DefaultRadix__ (10)



template<typename ValueType, typename CharType>
inline bool TryFromString(const CharType* str, ValueType& value, int radix = __Zaf_FromString_DefaultRadix__) {

	//Check empty string
	if (str[0] == 0) {
		return false;
	}

	//Check blank chars
	if (IsSpace(str[0])) {
		return false;
	}

	//Check sign chars
	if (radix != 10 && (str[0] == '-' || str[0] == '+')) {
		return false;
	}

	CharType* end;
	ValueType tmpValue;
	if (__Internal::__S2N(str, &end, radix, tmpValue) == false) {
		return false;
	}

	//Check whether whole string has been converted.
	if (end[0] != 0) {
		return false;
	}

	value = tmpValue;

	return true;
}



template<typename ValueType, typename CharType>
inline bool TryFromString(const std::basic_string<CharType>& str, ValueType& value, int radix = __Zaf_FromString_DefaultRadix__) {
	return TryFromString(str.c_str(), value, radix);
}



template<typename ValueType, typename CharType>
inline ValueType FromString(const CharType* str, int radix = __Zaf_FromString_DefaultRadix__) {
	ValueType value = ValueType();
	TryFromString(str, value, radix);
	return value;
}



template<typename ValueType, typename CharType>
inline ValueType FromString(const std::basic_string<CharType>& str, int radix = __Zaf_FromString_DefaultRadix__) {
	return FromString<ValueType>(str.c_str(), radix);
}


}  // String
}  // Zaf